package register

import (
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	logger "gitee.com/zaper/private-logger"
	"gitee.com/zaper/service-center-client/constant"
	"gitee.com/zaper/service-center-client/service/eth_manager"
	"gitee.com/zaper/service-center-client/service/service_info"
	"gitee.com/zaper/service-center-client/util"
	fmkutil "gitee.com/zaper/software-framework/util"
	"os"
	"sync"
	"time"
)

const (
	registerInterface = "/api/v1/service/register"
)

var (
	registerClientManagerOnce   sync.Once
	registerClientManagerSingle *RegisterClientManager
)

type RegisterClientManager struct {
	Port       string
	httpClient *fmkutil.HttpClientManager
	instance   *service_info.InstanceInfo
	sw         sync.Mutex
}

func GetRegisterClientManager() *RegisterClientManager {
	registerClientManagerOnce.Do(func() {
		registerClientManagerSingle = &RegisterClientManager{
			httpClient: fmkutil.NewHttpClientManager(),
		}
	})
	return registerClientManagerSingle
}

func (registerClientManager *RegisterClientManager) register() (string, bool) {
	logger.Infof("[service-center] Start register service")
	registerClientManager.instance = new(service_info.InstanceInfo)
	if err := registerClientManager.flushInstanceInfo(); err != nil {
		return "", false
	}
	request, err := json.Marshal(registerClientManager.instance)
	if err != nil {
		return "", false
	}
	registerUrl := fmt.Sprintf("%s%s%s",
		"https://", os.Getenv(constant.ResisterCenterKey), registerInterface)
	resp, err := registerClientManager.httpClient.Post(registerUrl, constant.ContentType, bytes.NewReader(request))
	if err != nil {
		return "", false
	}
	return parseRegisterResult(resp)
}

func (registerClientManager *RegisterClientManager) keepAlive(leaseID string) (string, bool) {
	logger.Infof("[service-center] keepAlive serviceName is %s, leaseId %s", registerClientManager.instance.Name, leaseID)
	registerClientManager.instance.Metadata = make(map[string]string)
	registerClientManager.instance.Metadata["leaseID"] = leaseID
	request, err := json.Marshal(registerClientManager.instance)
	if err != nil {
		return "", false
	}
	registerUrl := fmt.Sprintf("%s%s%s",
		"https://", os.Getenv(constant.ResisterCenterKey), registerInterface)
	resp, err := registerClientManager.httpClient.Post(registerUrl, constant.ContentType, bytes.NewReader(request))
	if err != nil {
		return "", false
	}
	return parseRegisterResult(resp)
}

func (registerClientManager *RegisterClientManager) flushInstanceInfo() error {
	registerClientManager.sw.Lock()
	defer registerClientManager.sw.Unlock()
	registerClientManager.instance.ID = os.Getenv(constant.ID)
	registerClientManager.instance.Name = os.Getenv(constant.ServiceNameKey)
	ip, err := eth_manager.GetListenEth()
	if err != nil {
		return errors.New("GetListenEth fail")
	}
	registerClientManager.instance.Endpoints = []string{
		fmt.Sprintf("%s:%s", ip, registerClientManager.Port),
	}
	return nil
}

func (registerClientManager *RegisterClientManager) AutoFlushInstanceInfo() {
	ticker := time.NewTicker(60 * time.Second)
	go func() {
		for {
			select {
			case <-ticker.C:
				err := registerClientManager.flushInstanceInfo()
				if err != nil {
					logger.Errorf("autoFlushInstanceInfo fail, err is %s", err)
				}
			}
		}
	}()
}

func parseRegisterResult(r []byte) (string, bool) {
	response := &util.HttpResponseError{}
	err := json.Unmarshal(r, response)
	if err != nil {
		return "", false
	}
	if response.ErrorCode == 0 {
		leaseID := response.ErrorMess.(map[string]interface{})["LeaseID"].(string)
		return leaseID, true
	}
	return "", false
}
